// bzoj1187
// 题意：
// 给定一个n(<=100)*m(<=6)的棋盘，每个格子有一个可正可负的价值，现在要随便
// 选一个点做为起点，除了第一个点外，其他点至多走一次走一圈回到起点，
// 问能得到的最大价值是多少？
//
// 题解：
// 还是插头dp可以搞，依旧是回路，所以一个点可以没有插头或者两个插头。
// 然后用括号表示的时候，如果遇到某个更新点左插头是左括号，
// 上插头是右括号，接上他们就可以构成一个回路，
// 但是要注意这样可能还有其他路径，所以要判断当前状态只有两个插头，
// 然后更新答案就行。
//
// run: $exec < input
#include <iostream>
#include <iomanip>
#include <algorithm>

#define DEBUG 0

int const  inf = 1 << 28;
int const maxn = 107;
int a[maxn][10];
int n, m;

struct hash_table
{
	int static const maxsize = 2000;
	int key[maxsize];
	int hash[maxsize];
	int val[maxsize];
	int count;

	void clear()
	{
		count = 0;
		std::fill(key, key + maxsize, -1);
		std::fill(hash, hash + maxsize, 0);
		std::fill(val, val + maxsize, -inf);
	}

	void alloc_node(int p, int key_)
	{
		hash[p] = ++count;
		key[count] = key_;
	}

	int & operator[](int key_)
	{
		int p;
		for (int i = key_ % maxsize; ; i++) {
			if (i == maxsize) i = 0;
			if (!hash[i]) alloc_node(i, key_);
			if (key[hash[i]] == key_) {
				p = hash[i];
				break;
			}
		}
		return val[p];
	}
};

hash_table f[2];
int now, prev, ans = -inf;

int get(int st, int p) { return (st >> ((p - 1) << 1)) & 3; }

void change(int & st, int p, int v)
{
	int w = (p - 1) << 1;
	st &= (~0) ^ (3 << w);
	st |= v << w;
}

int find(int st, int p)
{
	for (int i = p, d = 0, step = get(st, p) == 1 ? 1 : -1; ; i += step) {
		d += get(st, i) == 1 ? 1 : -1;
		d += get(st, i) == 0 ? 1 : 0;
		if (!d) return i;
	}
	return -1;
}

int count_plug(int st)
{
	int ret = 0;
	for (int i = 1; i <= m + 1; i++)
		if (get(st, i)) ret++;
	return ret;
}

void print(int st)
{
	for (int i = 1; i <= m + 1; i++)
		std::cout << get(st, i);
}

void dp(int i, int j)
{
	now ^= 1; prev ^= 1;
	f[now].clear();
	for (int t = 1; t <= f[prev].count; t++) {
		int st = f[prev].key[t];
		int v = f[prev].val[t];

#if DEBUG
		std::cout << "(" << i << ", " << j << ") = " << std::setw(10) << v << " ";
		print(st);
		std::cout << "\n";
#endif

		int left = get(st, j);
		int up = get(st, j + 1);
		if (!left && !up) {
			f[now][st] = std::max(f[now][st], v);
			if (i != n && j != m) {
				change(st, j, 1);
				change(st, j + 1, 2);
				f[now][st] = std::max(f[now][st], a[i][j] + v);
			}
		} else if (left == up) {
			change(st, find(st, j + 2 - left), left);
			change(st, j, 0);
			change(st, j + 1, 0);
			f[now][st] = std::max(f[now][st], v + a[i][j]);
		} else if (left == 1 && up == 2) {
			int count = count_plug(st);
			if (count == 2) ans = std::max(ans, v + a[i][j]);
		} else if (left == 2 && up == 1) {
			change(st, j, 0);
			change(st, j + 1, 0);
			f[now][st] = std::max(f[now][st], v + a[i][j]);
		} else if (left) {
			if (i != n) f[now][st] = std::max(f[now][st], v + a[i][j]);
			if (j != m) {
				change(st, j, 0);
				change(st, j + 1, left);
				f[now][st] = std::max(f[now][st], v + a[i][j]);
			}
		} else if (up) {
			if (j != m) f[now][st] = std::max(f[now][st], v + a[i][j]);
			if (i != n) {
				change(st, j + 1, 0);
				change(st, j, up);
				f[now][st] = std::max(f[now][st], v + a[i][j]);
			}
		}
	}
}

int main()
{
	std::ios::sync_with_stdio(false);
	std::cin >> n >> m;
	for (int i = 1; i <= n; i++)
		for (int j = 1; j <= m; j++)
			std::cin >> a[i][j];
	now = 0; prev = 1;
	f[0][0] = 0;

	for (int i = 1; i <= n; i++) {
		for (int j = 1; j <= m; j++) dp(i, j);
		if (i == n) continue;
		for (int j = 1; j <= f[now].count; j++)
			f[now].key[j] <<= 2;
	}
	std::cout << ans << "\n";
}

